查看原文
其他

WireGuard 真的很香吗?香个屁!

米开朗基杨 云原生实验室 2021-05-26


该文章随时会有校正更新,公众号无法更新,欢迎订阅博客查看最新内容:https://fuckcloudnative.io

前言

最近有一款新型 VPN 工具备受瞩目,相信很多人已经听说过了,没错就是 WireGuard,传言它有望取代 IPSecOpenVPN。那么 WireGuard 是否真的有传说中的那么神奇?今天我就来一一解读。

这是一篇非常长的文章,我建议你先去冲杯咖啡,然后边喝咖啡边看。

首先要声明:我并没有诋毁 WireGuard 的意思,WireGuard 很棒很优秀,但总是有某些无脑媒体天天说 WireGuard 即将取代 IPSecOpenVPN,这我就不能忍了,今天就来和你们好好掰扯掰扯 WireGuard。

WireGuard 白皮书

本文所有的观点都是针对 Jason Donenfeld 撰写的 WireGuard 白皮书,其他的博客和文档不在我的讨论范围之内。白皮书的第一句话是这么说的:

WireGuard 的目标是在大多数场景下取代 IPsec 和其他基于用户空间和 TLS 的 VPN(例如 OpenVPN),与其他 VPN 相比,它更简单、更高效、更容易使用。

可以看到,WireGuard 最大的卖点就是简单,大多数新技术也都是这个营销套路。当然,作为一款 VPN 产品,它还有性能和安全这两个卖点。

有趣的是,作为 VPN,如果你不简单、不安全、性能不好,那你可能就没有机会了。这不止是你 WireGuard 的设计目标,其他的 VPN 产品也是这么干的好吗?

最有趣的部分是“在大多数场景下”这几个字,媒体报道时直接将其删除了,混淆大众的视听。

WireGuard 能否取代 IPSec?

不!CiscoJuniper 等大厂不可能使用 WireGuard,除非迫不得已,他们是不会上 WireGuard 的车的。后面我会详细解释为什么即使他们想卖 WireGuard 服务也卖不出去。

WireGuard 实现了 Road Warrior?

当然没有。Road Warrior 是具有动态分配 IP 地址的移动客户端,比如笔记本电脑。你可以直接理解为漫游。WireGuard 目前不能使用动态 IP 来建立连接,要想实现漫游功能,还有很长的路要走。

WireGuard 有一个子项目叫 wg-dynamic[1],它增加了一个用户空间守护程序来使 WireGuard 支持动态 IP。然而这个项目最后一次更新是在 2019 年,不知道还维护不维护了。。。

大家都知道,IPv6 就是动态寻址的,如果将来全面进入 IPv6 的世界,WireGuard 还怎么用?从商业角度来看,这是相当令人失望的。

WireGuard 的设计目标之一是保持协议的精简,现在看来是精简过头了,以至于需要更多的辅助软件才能使它发挥强大的功效。

WireGuard 真的好用吗?

并没有。我并没有说 WireGuard 最终不能替代其他 VPN 产品,我只是说目前 WireGuard 还不行,如果它的目标和我们理解的一样,目前它还只是处在 Alpha 阶段。

WireGuard 到底想解决什么问题?IPsec 真的很难用吗?

恐怕不是这样,如果厂商做了正确的功课,并提供了易于使用的界面(比如,IPFire[2]),就不会难用。

要想建立一个 IPSec 隧道,只需要输入 5 组信息:你的公网地址、peer 的公网地址、子网、你的预共享秘钥和 peer 的预共享秘钥。这样看来,几分钟就可以建立一个隧道,而且每个厂商之间都是兼容的。

当然,也有一些例外,比如与 OpenBSD 系统之间建立隧道,过程可能会比较痛苦。

协议复杂度真的很重要吗?

作为终端用户,其实无需考虑协议的复杂度。

如果复杂度真的影响很大,我们肯定早就摆脱 SIPH.323FTP 等不能很好地应对 NAT 的协议了,然而并没有。讲道理,IPsec 比 WireGuard 更复杂是有原因的:**它能做的事情太多了。**比如,使用用户名/密码或带有 EAPSIM 卡进行用户认证;也可以扩展新的加密方式。

而 WireGuard 呢?这些功能都没有。这就意味着当某一天它的固定的那些加密方式被破解或削弱了之后,就彻底崩盘了。

WireGuard 作者说过:

WireGuard 在加密方式上比较偏执,故意砍掉了加密协议的敏捷性,不支持扩展加密协议,因为这么做会大大降低软件的复杂度。如果底层的加密协议出现了漏洞,只能更新所有端点来修复漏洞。

我非常同意他这句话里阐述的观点,因为协商使用何种方式来加密会使 IKETLS 等协议变得更复杂。那么,是我们想不开刻意要搞这么复杂吗?当然不是啊,即使这样,在握手过程中也会经常发现各种漏洞,不复杂能行吗?除此以外,别无他法。

如何更新密码?

想象一下,你有一个 VPN 服务器,为 200 多个 Road Warrior 客户端提供服务,而且这些客户端分布在世界各地。假设现在你改了密码,那么就需要同时更新所有客户端的密码才能正常工作,这简直就是不可能的事情,作为管理员,你可能会需要几个月的时间来下方更改后的配置。

IPsecOpenVPN 就没有这些烦恼,它们都有秘钥协商功能,可以将新秘钥逐步更新到所有客户端,在漫长的更新过程中,仍在使用旧秘钥的客户端仍然有效,直到所有客户端更新完毕后,才会弃用旧秘钥。整个过程中客户端不会有任何察觉,也不需要重启。

加密方式

WireGuard 使用以下加密技术来保障数据的安全:

  • 使用 ChaCha20 进行对称加密,使用 Poly1305 进行数据验证。
  • 利用 Curve25519 进行密钥交换。
  • 使用 BLAKE2 作为哈希函数。
  • 使用 HKDF 进行解密。

而 IPSec 和 OpenVPN 使用的都是标准的 ChaCha20-Poly1305 加密算法。

BLAKE2算法是 BLAKE 算法的升级版,而 BLAKESHA-3 的入围者,与 SHA-2 非常相似,所以没有获奖。如果哪天 SHA-2 被破解了,BLAKE 也很有可能被破解。

IPSec 和 OpenVPN 使用的加密方式和 WireGuard 是类似的,比如对称加密使用的是标准的 ChaCha20-Poly1305 算法。唯一没有用到的就是 BLAKE2,因为它目前没有列入标准。即使不用 BLAKE2,也没什么大不了的,因为 VPN 是使用 HMACs 来保障数据的完整性,即使使用 MD5 也仍然没问题。

我的结论是:实际上所有的 VPN 都可以使用相同的加密技术,WireGuard 在加密或数据完整性方面并没有比其他的 VPN 更安全或更不安全。

然而白皮书上说了,加密不是重点,速度才是。

好吧,那我们就来看看速度是不是真的有那么快。

WireGuard 真的很快吗?

答案是否定的。

ChaCha20 是一种流加密算法,一次只加密一个比特,使用软件更容易实现。而像 AES 这样的分块加密方式,会将明文分成多个等长的模块,每次加密 128 位的模块。这种加密方式在硬件中实现时需要更多的晶体管,所以大型处理器都带有一个指令集扩展 -- AES-NI[3],它可以提高加密和解密的速度。

今天你能买到的任何一款智能手机都带有 AES 的硬件加速功能,在这些硬件中使用 AES 会比 ChaCha20 加密解密更快、更节能。几乎所有的个人 PC 和服务器的 CPU 都带有 AES-NI,加密解密速度就更不用说了。因此,我预计 AES 在几乎所有场景下表现都会优于 ChaCha20

然而,WireGuard 的白皮书又说了,ChaCha20-Poly1305 的性能优于 AES-NI,但该指令集只适用于大型处理器,对普通 PC 和移动硬件没有任何帮助,所以并没有什么卵用。

WireGuard 执着于一种加密算法,我觉得不好。而 IPSec 允许你选择不同的加密算法,这样就可以根据不同的使用场景选择最合适的加密算法,例如,传输 10G 或更多的数据[4]

既然 WireGuard 选择了更现代的加密方式,就会带来很多问题。比如,由于 Linux 内核中缺乏支持这些加密方式的模块,导致 WireGuard 并没有使用 Linux 内核提供的模块,要推迟好几年才能用上 Linux 内核提供的模块。我不知道其他操作系统是什么情况,但可能也没有什么不同。

理想与现实

假设 WireGuard 真的很完美,大厂就一定会用吗?

现实情况是,每次当客户要求我帮他们搭建 VPN 时,给到他们手里的证书都是使用旧的加密方式,通常是 3DESMD5 结合,或者 AES-256SHA1 结合。至于秘钥交换,我们一直在使用 RSA,虽然速度很慢,但足够安全。

大部分客户都和政府机构或巨头公司有关,他们在我们这里的订单表还是几十年前的,根本就没有添加过 SHA-512 的选项。所以阻止创新的不一定是技术,而是缓慢的企业流程。

看到这种情况,我也很痛心?我就不想使用新技术吗?当然想啊。IPsec 从 2005 年左右就开始支持椭圆曲线加密算法了,Curve25519 算法现在也支持了,也有了 AES 的替代方案(比如 CamelliaChaCha20),但很显然并不是所有的大厂都愿意去适配,比如思科等。思科是这个领域的市场领导者,他们对推动创新其实并不感兴趣。

基准测试

白皮书中还提到了 WIreGuard 的基准测试,虽然这不是一篇科学论文,但我仍然希望以科学的方法来进行基准测试。如果测试不能重复,那么它就毫无价值;如果测试没有考虑实际场景,也毫无价值。

WireGuard 的 Linux 版本使用 GSO(Generic Segmentation Offloading,通用分段卸载)来创建一个 64k 字节的巨大数据包,并一次性对其进行加密或解密,以此来获得速度优势。这样一来,初始化和调用加密操作的开销就被节省了。如果你想最大限度地提高吞吐量,这倒是一个好主意。

然而现实不是这样的,你想向网络适配器发送如此大的数据包,就需要将其切割成许多小数据包,通常为 1500 字节。对于 64k 字节的超大数据包来说,会被切割成 45 个数据包(每个数据包有 1480 字节的有效载荷和 20 字节的 IP 头),这些数据包将会阻塞网络适配器相当长的时间,因为它们想要被一次性发送出去。像 VoIP 呼叫这样应该优先处理的数据包也不得不慢慢等着。

因此,WireGuard 宣称的高吞吐量是通过让其他应用变慢来获得的,官方团队已经承认了这一点。

我们再来看看基准测试的最终数据,吞吐量为 1011 MBit/s

这个数据令人印象深刻,我至今仍感到疑惑,在数据包大小为 1500 字节的情况下,一个千兆以太网链路的最大理论吞吐量为 966 MBit/s,减去 20 个字节的 IP 头、8 个字节的 UDP 头和 16 个字节的 WireGuard 头,再减去封装数据包中的另一个 IP 头和另一个 20 个字节的 TCP 头,额外的带宽到底从哪来的?

OK,假设启用了巨型帧和 GSO9000 字节帧大小时的理论最大值将是 1014 MBit/s。如果使用更大的巨型帧,理论最大值为 1023 MBit/s。然而这在现实中是绝对不实用的,因为开销太大了,而且只能在服务器直连的情况下使用。通常 VPN 都是通过互联网连接的,完全不支持巨型帧,所以这样的基准测试根本不切实际,永远不可能在现实世界中使用。

最终幻想

WireGuard 的官方网站写了很多关于容器的内容,很明显这应该就是 WireGuard 的真实目的。

通过一个简单迅速的 VPN 来实现容器通信的 CNI,可以通过 Kubernetes 等大型容器编排工具来快速部署,针对吞吐量和大于 9000 字节的数据包进行了优化,可以快速分发容器镜像,等等。

这一切的种种都好像是为容器而设计的,不得不承认,超精简、超优雅、超快速。

但是,它根本不是为数据中心以外的世界而设计的,在外面的世界,你必须要在协议的设计和实现上做出妥协。

总结

我最终的结论是:WireGuard 还没有准备好。

它是作为一个轻量级和快速的解决方案来起草的,以解决现有解决方案中的一些问题,但不幸的是,它牺牲了许多与用户相关的功能,因此无法取代 IPsec 和 OpenVPN。

你至少得有动态地址分配和推送路由等配置的功能吧?这些功能都是需要进行秘钥协商的。

此外,安全性是重中之重,目前我还没发现 IKE 或者 TLS 有啥明显的缺陷,它们都支持现代加密方式,而且都经过了几十年的审计。不能仅仅因为某些东西是新的,就觉得它是好的。

加密方式总会过时,押注在一种加密方式身上,当这种加密方式不再安全时,你该何去何从?

参考资料

[1]

wg-dynamic: https://git.zx2c4.com/wg-dynamic/about/docs/idea.md

[2]

IPFire: https://www.ipfire.org

[3]

AES-NI: https://zh.wikipedia.org/wiki/AES%E6%8C%87%E4%BB%A4%E9%9B%86

[4]

传输 10G 或更多的数据: https://blog.ipfire.org/post/feature-spotlight-galois-counter-mode-ipsec-with-10g


原文链接:https://blog.ipfire.org/post/why-not-wireguard



你可能还喜欢

点击下方图片即可阅读

别看 DNS 污染闹得欢,现在我用 CoreDNS 将它拉清单

云原生是一种信仰 🤘



码关注公众号

后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!



点击 "阅读原文" 获取更好的阅读体验!

❤️给个「在看」,是对我最大的支持❤️

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存